Skip to content

Improve ACL tab performance by lazy fetching - #1660

Open
Arnei wants to merge 8 commits into
opencast:r/20.xfrom
Arnei:acl-role-picker-server-search
Open

Improve ACL tab performance by lazy fetching#1660
Arnei wants to merge 8 commits into
opencast:r/20.xfrom
Arnei:acl-role-picker-server-search

Conversation

@Arnei

@Arnei Arnei commented Aug 24, 2026

Copy link
Copy Markdown
Member

Includes #1655.
Requires backend changes: opencast/opencast#7958

The Access Policy tab (and the corresponding wizards) fetched every role in the system (limit: -1) on open to populate each role dropdown client-side. On instances with many thousands of roles this was a multi-second, multi-megabyte request fired once per open.

This PR implements a suggestion made by @ltekbas in #1442, more specifically the "typeahead input". Roles are not eagerly fetched anymore, but only when a role dropdown is clicked on or searched in. Furthermore, the fetch request (and thus the dropdown options) set a limit of 50. Figuring out which role are user roles (for Opencasts with role sanitization disabled) is now done in the backend, further reducing load (and is the thing that allows us to drop eager fetching in the first place).

Pros:

  • ACL tab loads faster
  • Role dropdowns are more responsive

Cons:

  • The limited number of roles may trick users into thinking that there are less roles then there actually are.
  • Relies heavily on role search, meaning users need to know role or user names. This may hurt users who rely on seeing roles ("I don't remember how that role is called exactly but I'll know it when I see it").

I tested this on a local instance with 10.000 users, where it performed well. I am still somewhat concerned about the usability implications of this change, so ideally we get this tested by our heavy users.

Short demo:
Bildschirmaufzeichnung vom 2026-08-24 10-52-37.webm

How to test this

Requires an Opencast with the necessary backend changes, but that should be it.

AI Usage

Claude Sonnet was used for analyzing if a typeahead search dropdown was even possible in this case, and for making the necessary changes.

Arnei added 8 commits August 24, 2026 10:59
This was already false per default, but was set to
false explicitly to fix a tab navigation issue in the
metadata tab of events/series dialog.
So this sets openMenuOnFocus to false in RenderFields, so that it
may be true in other components again
Before we only made a copy if skipTranslate was true. This could
have cause errors with immutable arrays, so it is probably
better to copy everytime.
menuPlacement defaults to this anyway, no need to check
here again
By using useRef instead of createRef we can avoid
recreating the ref all the time.
Should result in a very, very minor performance boost.
Avoid potential rerenders for virtualized options
which can end up quite costly for larger lists.
Could also help with flickering and focus reset issues somewhat.
Previous code was just delaying the fetch by a second. It would still
fire all accumulated request anyway (e.g. requests for "C", "Co, "Cou",
"Cour", "Cours" and "Course", instead of just "Course".
Implements debouncing, which should make for less load
and cleaner rendering steps when searching in an async dropdown.
The 1s debounce delay predates the backend performance work on the ACL
role picker (see the opencast20-side fixes for /admin-ng/acl/roles.json):
when a search could take several seconds regardless, an extra second of
debounce was a small fraction of the total wait. Now that a real search
responds in roughly 100ms, the fixed 1s delay is the dominant, and now
clearly excessive, part of the perceived latency -- pull it down to 300ms,
in line with typical search-as-you-type debounce intervals, and give it a
name instead of a bare literal so it's easy to find and retune later.
The Access Policy tab (and the corresponding wizards) fetched every
role in the system (limit: -1) on open to populate each role dropdown
client-side. On instances with many thousands of roles this was a
multi-second, multi-megabyte request fired once per open.

fetchRolesWithTarget now accepts query/limit/offset/hasUser, and
AccessPolicyTable's role dropdowns search the backend as the user
types instead. The parent components only fetch a single role up
front, just to read the isSanitize flag that decides whether users
and non-user roles are split into separate tables.

DropDown gains a loadOptionsOnMount flag so a fetchOptions-based
dropdown can skip its eager default-option fetch on mount (used here
since AccessPolicyTable renders one dropdown per existing policy row,
which would otherwise fire one identical request per row on tab open)
and instead fetch its default option list lazily, the first time that
particular instance is opened. This also fixes the virtualized
MenuList silently rendering nothing instead of react-select's
no-options/loading message when there are no options yet.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant